package com.icee.myth.server.actor;

import com.icee.myth.common.charInfo.CharDetailInfo;
import com.icee.myth.common.messageQueue.DBMessageQueue;
import com.icee.myth.common.messageQueue.ServerMessageQueue;
import com.icee.myth.common.protobufMessage.ProtobufMessage;
import com.icee.myth.config.MapConfig;
import com.icee.myth.config.VipNumGold;
import com.icee.myth.log.GameLogger;
import com.icee.myth.log.message.FileDebugGameLogMessage;
import com.icee.myth.log.message.GameLogMessage;
import com.icee.myth.log.message.builder.GameLogMessageBuilder;
import com.icee.myth.protobuf.ExternalCommonProtocol.*;
import com.icee.myth.protobuf.InternalCommonProtocol.PlayerDetailProto;
import com.icee.myth.protobuf.builder.ClientToMapBuilder;
import com.icee.myth.server.GameServer;
import com.icee.myth.server.activity.cardDrawActivity.CardDrawActivityTemplates;
import com.icee.myth.server.activity.normalActivity.NormalActivity;
import com.icee.myth.server.activity.stageActivity.StageActivityTemplates;
import com.icee.myth.server.base.BaseTargets;
import com.icee.myth.server.base.barrack.Barrack;
import com.icee.myth.server.base.council.Council;
import com.icee.myth.server.base.mine.Mine;
import com.icee.myth.server.base.occupy.OccupyInfo;
import com.icee.myth.server.base.occupy.OccupyInfos;
import com.icee.myth.server.base.ordnance.Ordnance;
import com.icee.myth.server.base.training.Training;
import com.icee.myth.server.battle.*;
import com.icee.myth.server.bill.Bill;
import com.icee.myth.server.bill.Order;
import com.icee.myth.server.card.Card;
import com.icee.myth.server.card.CardFactories;
import com.icee.myth.server.card.CardStaticInfo;
import com.icee.myth.server.card.Cards;
import com.icee.myth.server.card.cardDraw.CardDrawItem;
import com.icee.myth.server.card.cardDraw.CardDrawStaticInfo;
import com.icee.myth.server.card.cardDraw.CardDrawsConfig;
import com.icee.myth.server.contsign.ContSign;
import com.icee.myth.server.fighter.Fighter;
import com.icee.myth.server.hegemony.HegemonyTarget;
import com.icee.myth.server.hegemony.HegemonyTargets;
import com.icee.myth.server.index.PlayerIdsOfLevels;
import com.icee.myth.server.index.PlayerIdsOfRanks;
import com.icee.myth.server.item.Items;
import com.icee.myth.server.levelup.HumanLevelsConfig;
import com.icee.myth.server.levelup.HumanRankConfig;
import com.icee.myth.server.levelup.HumanRanksConfig;
import com.icee.myth.server.mail.Mails;
import com.icee.myth.server.message.dbMessage.builder.MapDBMessageBuilder;
import com.icee.myth.server.message.serverMessage.builder.MapMessageBuilder;
import com.icee.myth.server.notification.NotifySystem;
import com.icee.myth.server.notification.message.BillNotificationMessage;
import com.icee.myth.server.player.MapPlayer;
import com.icee.myth.server.quest.Quests;
import com.icee.myth.server.reward.CertainRewardInfo;
import com.icee.myth.server.reward.RewardItemInfo;
import com.icee.myth.server.sandbox.SandBox;
import com.icee.myth.server.sandbox.TargetSandbox;
import com.icee.myth.server.sandbox.TargetSandboxCard;
import com.icee.myth.server.social.BriefPlayerInfo;
import com.icee.myth.server.social.Relation;
import com.icee.myth.server.stage.*;
import com.icee.myth.server.talent.TalentStaticInfo;
import com.icee.myth.server.talent.TalentsConfig;
import com.icee.myth.server.timer.FlushDataTimer;
import com.icee.myth.server.timer.MTimer;
import com.icee.myth.server.vip.Vip;
import com.icee.myth.server.vip.VipGift;
import com.icee.myth.utils.Consts;
import com.icee.myth.utils.RandomGenerator;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

 /**
  *
  * @author liuxianke
  */
 public class Human {

     public final int id;    // 玩家id
     public String name;     // 玩家名字
     public int lv;          // 玩家等级
     public int exp;         // 玩家经验
     public int rankLv;      // 玩家军衔等级
     public int rankExp;     // 玩家军衔经验（功勋）
     public int gold1;       // 黄金（充值）
     public int gold2;       // 黄金（非充值）
     public long silver;     // 白银
     public int energy;      // 体力
     public int token;       // 军令

     public int guideStep;     // 新手引导步骤号

     public Items items;     // 物品
     public Cards cards;     // 卡片背包

     public SandBox sandbox;
     public int maxPower;    // 历史最大战斗力

     public final Stages stages; // 关卡信息
     public Stage stage;             // Human所在的关卡（注意：Human不能同时在场景和关卡中，挑战时不能进入关卡）

     public Vip vip;         // vip
     public VipGift vipGift; // vip赠礼

     public int ip;          // 玩家登陆ip
     public long enterTime;  // 最近一次登陆游戏时间
     public long leaveTime;  // 最后一次离开游戏时间
     public long totalOnlineTime;    // 累计游戏时间
     public long nextWorldTalkTime;      // 下次允许世界频道发言时间
     public long nextBattlePermitTime;   // 下一次战斗录像许可观看时间

     public Quests quests;   // 任务

     public MapPlayer mapPlayer;    // Human角色对应的网络实体
     public boolean inGame = false;  // 游戏中标志
     public boolean hasCharged = false;   // 是否充值过

     // 签到
     public ContSign contSign;
     // 好友关系
     public Relation relation;
     // 助战陌生人
     public final LinkedList<BriefPlayerInfo> strangers = new LinkedList<BriefPlayerInfo>();

     public int lastBuyEnergyDay;  //最近购买体力的日期
     public int buyEnergyCount;    //最近购买体力的日期那一天的购买次数

     public Mails mails;     // 补偿

     public NormalActivity normalActivity;   // 普通活动

     public HegemonyTargets hegemonyTargets; // 争霸对手

     public int lastRefreshHegemonyDay;  // 最近刷新争霸列表的日期
     public int refreshHegemonyCount;    // 最近刷新争霸列表的日期那一天的刷新次数
     public int lastHegemonyPayDay;      // 最后一次领争霸军饷的日期

     public BaseTargets baseTargets;     // 据点征服目标（只有在列表中的目标才能征服）（不需存数据库）
     public OccupyInfo selfOccupyInfo;   // 注意：当玩家正在反抗时才设置该值，即当该值不为null时表示正在反抗
     public Training training;           // 城墙
     public Mine mine;                   // 银矿
     public Barrack barrack;             // 兵营
     public Ordnance ordnance;           // 军械所
     public Council council;             // 军机处

     private FlushDataTimer flushTimer; // 数据库刷新计时器
     public HumanUpdateTimer updateTimer = null;   // 角色场景刷新定时器
     public final HumanProtocolBuilder humanProtocolBuilder = new HumanProtocolBuilder();

     public class HumanProtocolBuilder {

         public PlayerDetailProto buildPlayerDetail() {
             PlayerDetailProto.Builder builder = PlayerDetailProto.newBuilder();

             builder.setCards(cards.buildCardsProto()); // 卡片信息
             builder.setItems(items.buildItemsProto()); // 物品信息
             builder.setStages(stages.buildStagesProto()); // 关卡信息

             builder.setSandbox(sandbox.buildSandboxProto());
             builder.setBuyEnergyCount(buyEnergyCount);
             builder.setLastBuyEnergyDay(lastBuyEnergyDay);
             builder.setNormalActivity(normalActivity.buildDBNormalActivityProto());
             builder.setQuests(quests.buildQuestsProto());
             builder.setVipLastDayExp(vip.lastDayExp);
             builder.setViplastExpDay(vip.lastExpDay);
             builder.setVipGift(vipGift.receiveFlag);

             builder.setContSign(contSign.buildDBContSignProto());

             builder.setGuideStep(guideStep);

             if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                 assert (hegemonyTargets != null);
                 builder.setRefreshHegemonyCount(refreshHegemonyCount);
                 builder.setLastRefreshHegemonyDay(lastRefreshHegemonyDay);
                 builder.setLastHegemonyPayDay(lastHegemonyPayDay);
                 builder.setHegemonyTargets(hegemonyTargets.buildDBHegemonyTargetsProto());
             }

             if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                 assert (training != null);
                 builder.setTraining(training.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openMineLevel) {
                 assert (mine != null);
                 builder.setMine(mine.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                 assert (barrack != null);
                 builder.setBarrack(barrack.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                 assert (ordnance != null);
                 builder.setOrdnance(ordnance.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                 assert (council != null);
                 builder.setCouncil(council.buildSlotsProto());
             }

             return builder.build();
         }

         public EnterGameCharProto buildEnterGameCharProto() {
             EnterGameCharProto.Builder builder = EnterGameCharProto.newBuilder();

             builder.setCid(id);
             builder.setName(name);
             builder.setGold1(gold1);
             builder.setGold2(gold2);
             builder.setSilver(silver);
             builder.setEnergy(energy);
             builder.setToken(token);
             builder.setLv(lv);
             builder.setExp(exp);
             builder.setRankLv(rankLv);
             builder.setRankExp(rankExp);
             builder.setMaxPower(maxPower);

             builder.setCards(cards.buildCardsProto()); // 卡片信息
             builder.setItems(items.buildItemsProto()); // 物品信息
             builder.setStages(stages.buildStagesProto()); // 关卡信息

             if (stage != null) {
                 builder.setStageState(stage.buildStageStateProto());
             }

             builder.setSandbox(sandbox.buildSandboxProto());

             builder.setVip(vip.buildVipProto());
             builder.setVipGift(vipGift.receiveFlag);

             builder.setQuests(quests.buildQuestsProto());

             builder.setContSign(contSign.buildContSignProto());

             builder.setGuideStep(guideStep);

             builder.setBuyEnergyCount(buyEnergyCount);
             builder.setLastBuyEnergyDay(lastBuyEnergyDay);

             builder.setCurrentTime(GameServer.INSTANCE.getCurrentTime());
             builder.setEndForbidTalkTime(mapPlayer.endForbidTalkTime);

             if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                 assert (hegemonyTargets != null);
                 builder.setRefreshHegemonyCount(refreshHegemonyCount);
                 builder.setLastRefreshHegemonyDay(lastRefreshHegemonyDay);
                 builder.setLastHegemonyPayDay(lastHegemonyPayDay);
                 builder.setHegemonyTargets(hegemonyTargets.buildHegemonyTargetsProto());
             }

             if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                 assert (training != null);
                 builder.setTraining(training.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openMineLevel) {
                 assert (mine != null);
                 builder.setMine(mine.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                 assert (barrack != null);
                 builder.setBarrack(barrack.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                 assert (ordnance != null);
                 builder.setOrdnance(ordnance.buildSlotsProto());
             }

             if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                 assert (council != null);
                 builder.setCouncil(council.buildSlotsProto());
             }

             return builder.build();
         }
     }

     public class HumanUpdateTimer implements MTimer {

         @Override
         public boolean update(int difftime) {
             if (this == updateTimer) {
                 Human.this.update(difftime);
                 return true;
             } else {
                 return false;
             }
         }
     }

     // 注意：Human构造是在主线程中调用
     public Human(int id, CharDetailInfo charDetailInfo) {
         assert (id == charDetailInfo.mid);
         this.id = id;
         this.name = charDetailInfo.name;
         this.gold1 = charDetailInfo.gold1;
         this.gold2 = charDetailInfo.gold2;
         this.silver = charDetailInfo.silver;
         this.energy = charDetailInfo.energy;
         this.token = charDetailInfo.token;
         this.lv = charDetailInfo.level;
         this.exp = charDetailInfo.experience;
         this.rankLv = charDetailInfo.rankLevel;
         this.rankExp = charDetailInfo.rankExperience;

         this.totalOnlineTime = charDetailInfo.totalOnlineTime;
         this.leaveTime = charDetailInfo.leaveTime;

         PlayerDetailProto detail = charDetailInfo.detail;
         if (detail != null) {
             // 从detail中恢复数据
             buyEnergyCount = detail.getBuyEnergyCount();
             lastBuyEnergyDay = detail.getLastBuyEnergyDay();

             guideStep = detail.getGuideStep();

             // 卡片背包
             cards = new Cards(this, detail.getCards());
             // 材料背包
             items = new Items(this, detail.getItems());
             // 关卡信息
             stages = new Stages(this, detail.getStages());
             // 布阵信息
             sandbox = new SandBox(this, detail.getSandbox());
             // vip信息
             vip = new Vip(this, charDetailInfo.vipLevel, charDetailInfo.vipExperience, detail.getVipLastDayExp(), detail.getViplastExpDay());
             // vip赠礼
             vipGift = new VipGift(this, detail.getVipGift());

             // 签到
             contSign = new ContSign(this, detail.getContSign());
             // 补偿
             mails = new Mails(this, charDetailInfo.mailInfo);
             // 活动
             if (detail.hasNormalActivity()) {
                 normalActivity = new NormalActivity(this, detail.getNormalActivity());
             } else {
                 normalActivity = new NormalActivity(this, null);
             }
             // 任务
             if (detail.hasQuests()) {
                 quests = new Quests(this, detail.getQuests());
             } else {
                 quests = new Quests(this, null);
             }

             // 争霸
             if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                 refreshHegemonyCount = detail.getRefreshHegemonyCount();
                 lastRefreshHegemonyDay = detail.getLastRefreshHegemonyDay();
                 lastHegemonyPayDay = detail.getLastHegemonyPayDay();
                 if (detail.hasHegemonyTargets()) {
                     hegemonyTargets = new HegemonyTargets(this, detail.getHegemonyTargets());
                 } else {
                     hegemonyTargets = new HegemonyTargets(this, null);
                 }
             }

             // 城墙
             if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                 if (detail.hasTraining()) {
                     training = new Training(this, detail.getTraining());
                 } else {
                     training = new Training(this, null);
                 }
             }

             // 银矿
             if (lv >= MapConfig.INSTANCE.openMineLevel) {
                 if (detail.hasMine()) {
                     mine = new Mine(this, detail.getMine());
                 } else {
                     mine = new Mine(this, null);
                 }
             }

             // 兵营
             if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                 if (detail.hasBarrack()) {
                     barrack = new Barrack(this, detail.getBarrack());
                 } else {
                     barrack = new Barrack(this, null);
                 }
             }

             // 军械所
             if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                 if (detail.hasOrdnance()) {
                     ordnance = new Ordnance(this, detail.getOrdnance());
                 } else {
                     ordnance = new Ordnance(this, null);
                 }
             }

             // 军机处
             if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                 if (detail.hasCouncil()) {
                     council = new Council(this, detail.getCouncil());
                 } else {
                     council = new Council(this, null);
                 }
             }

         } else {
             energy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;

             guideStep = 1;

             // 卡片背包
             cards = new Cards(this, null);
             Card card = cards.addCard(charDetailInfo.leaderCardId, charDetailInfo.leaderCardLevel, 0, false);
             // 材料背包
             items = new Items(this, null);
             // 关卡信息
             stages = new Stages(this, null);
             // 布阵信息
             sandbox = new SandBox(this, null);
             sandbox.slots[0] = card;
             sandbox.leader = 0;
             sandbox.helper = 1;
             // vip信息
             vip = new Vip(this, charDetailInfo.vipLevel, charDetailInfo.vipExperience, 0, 0);
             // vip赠礼
             vipGift = new VipGift(this, 0);
             // 签到
             contSign = new ContSign(this, null);
             // 补偿
             mails = new Mails(this, null);
             // 普通活动
             normalActivity = new NormalActivity(this, null);
             // 任务
             quests = new Quests(this, null);

             // 争霸
             if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                 lastHegemonyPayDay = (int) ((GameServer.INSTANCE.getCurrentTime()+ Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                 hegemonyTargets = new HegemonyTargets(this, null);
             }

             // 城墙
             if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                 training = new Training(this, null);
             }

             // 银矿
             if (lv >= MapConfig.INSTANCE.openMineLevel) {
                 mine = new Mine(this, null);
             }

             // 兵营
             if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                 barrack = new Barrack(this, null);
             }

             // 军械所
             if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                 ordnance = new Ordnance(this, null);
             }

             // 军机处
             if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                 council = new Council(this, null);
             }
         }

         maxPower = charDetailInfo.maxPower;
         if (maxPower == 0) {
             maxPower = sandbox.getCurrentPower();
         }
     }

     public void setRelation(Relation relation) {
         if (this.relation == null) {
             relation.human = this;
             this.relation = relation;

             //send relation msg to client
             sendMessage(ClientToMapBuilder.buildRelationInfo(relation.buildRelationProto()));

             // 广播通知在线的follower该玩家上线
             if (!relation.friends.isEmpty()) {
                 ProtobufMessage protobufMessage = ClientToMapBuilder.buildFriendEntered(id);
                 for (Integer friendId : relation.friends.keySet()) {
                     MapPlayer friendPlayer = GameServer.INSTANCE.players.get(friendId);
                     if ((friendPlayer != null) && (friendPlayer.human != null) && (friendPlayer.human.inGame)) {
                         friendPlayer.human.sendMessage(protobufMessage);
                     }
                 }
             }

             // 产生助战陌生人
             generateStrangers(true);
         } else {
             // 若玩家快速登录下线再登录，能使Relation下消息队列中出现两个“get info”消息，此时会到该分支中，但概率很低
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] multi-set relation error."));
         }
     }

     private void generateStrangers(boolean needSend) {
         strangers.clear();
         GameServer.INSTANCE.briefPlayerInfos.getStrangers(lv, id, relation.friends, strangers);

         if (needSend) {
             // 通知客户端助战陌生人信息
             sendMessage(ClientToMapBuilder.buildStrangers(strangers, id));
         }
     }

     /**
      * 与离线上线时间差相关的刷新
      */
     public void timeRefresh() {
         if (leaveTime != 0) {
             if (enterTime > leaveTime) {    // 系统时间可能被修改
                 // 计算体力恢复
                 int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;
                 if (energy < maxEnergy) {
                     // 计算经过几次加体力周期
                     long num = enterTime / MapConfig.INSTANCE.energyRecoverPeriod - leaveTime / MapConfig.INSTANCE.energyRecoverPeriod;

                     energy = (int) ((energy + num < maxEnergy) ? energy + num : maxEnergy);
                 }

                 // 计算军令恢复
                 if (token < MapConfig.INSTANCE.maxTokenNum) {
                     // 计算经过几次加体力周期
                     long num = enterTime / MapConfig.INSTANCE.tokenRecoverPeriod - leaveTime / MapConfig.INSTANCE.tokenRecoverPeriod;

                     token = (int) ((token + num < MapConfig.INSTANCE.maxTokenNum) ? token + num : MapConfig.INSTANCE.maxTokenNum);
                 }
             }
         }
     }

     public long getSilver() {
         return silver;
     }

     public int getGold() {
         return gold1 + gold2;
     }

     public int getGold1() {
         return gold1;
     }

     public int getGold2() {
         return gold2;
     }

     public float getAtkUp() {
         return (ordnance != null)?ordnance.atkIncrease:0 + HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1].atkUp;
     }

     public float getHpUp() {
         return (barrack != null)?barrack.hpIncrease:0 + HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1].hpUp;
     }

     public int getHitAndDodUp() {
         return (training != null)?training.hitAndDodIncrease:0;
     }

     public int getCriAndTenUp() {
         return (council != null)?council.criAndTenIncrease:0;
     }

     public void checkMaxPowerChange() {
         // 判断是否需要更新历史最高战斗力
         int currentPower = sandbox.getCurrentPower();

         if (currentPower > maxPower) {
             maxPower = currentPower;
         }
     }

     /**
      * 新手引导
      * @param curGuildStep
      */
     public void nextGuide(int curGuildStep) {

         if (guideStep > 0) {
             if (guideStep == curGuildStep) {
                 switch (guideStep) {
                     case 16: {
                         // 获得第一关奖励
                         increaseExperience(121, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 16, true);
                         increaseSilver(878, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 16, true);

                         // 让第一关为通过状态（注意：附带会使第一个任务成为完成状态）
                         stages.finishState(0, false, true);

                         break;
                     }
                     case 19: {
                         // 完成第一个任务
                         quests.submit(0);

                         break;
                     }
                     case 23: {
                         // 更改阵型
                         SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                         VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                         VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                         builder3.setId(0);
                         builder3.setValue(1);
                         builder2.addValues(builder3);

                         VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                         builder4.setId(1);
                         builder4.setValue(2);
                         builder2.addValues(builder4);

                         builder1.setSlots(builder2);

                         builder1.setLeader(0);
                         builder1.setHelper(2);

                         sandbox.change(builder1.build());

                         break;
                     }
                     case 28: {
                         // 更改阵型
                         SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                         VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                         VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                         builder3.setId(0);
                         builder3.setValue(1);
                         builder2.addValues(builder3);

                         VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                         builder4.setId(4);
                         builder4.setValue(2);
                         builder2.addValues(builder4);

                         builder1.setSlots(builder2);

                         builder1.setLeader(0);
                         builder1.setHelper(2);

                         sandbox.change(builder1.build());

                         break;
                     }
                     case 32: {
                         // 获得第二关奖励
                         increaseExperience(123, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 32, true);
                         increaseSilver(514, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 32, true);
                         decreaseEnergy(10, true);

                         // 让第二关为通过状态（会使第二个任务成为完成状态）
                         stages.finishState(1, false, true);

                         break;
                     }
                     case 35: {
                         // 完成第二个任务S
                         quests.submit(1);

                         break;
                     }
                     case 39: {
                         // 更改阵型
                         SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                         VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                         VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                         builder3.setId(0);
                         builder3.setValue(1);
                         builder2.addValues(builder3);

                         VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                         builder4.setId(1);
                         builder4.setValue(3);
                         builder2.addValues(builder4);

                         VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                         builder5.setId(4);
                         builder5.setValue(2);
                         builder2.addValues(builder5);

                         builder1.setSlots(builder2);

                         builder1.setLeader(0);
                         builder1.setHelper(2);

                         sandbox.change(builder1.build());

                         break;
                     }
                     case 44: {
                         // 更改阵型
                         SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                         VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                         VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                         builder3.setId(1);
                         builder3.setValue(3);
                         builder2.addValues(builder3);

                         VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                         builder4.setId(3);
                         builder4.setValue(1);
                         builder2.addValues(builder4);

                         VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                         builder5.setId(4);
                         builder5.setValue(2);
                         builder2.addValues(builder5);

                         builder1.setSlots(builder2);

                         builder1.setLeader(3);
                         builder1.setHelper(2);

                         sandbox.change(builder1.build());
                         break;
                     }
                     case 50: {
                         // 更改阵型
                         SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                         VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                         VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                         builder3.setId(1);
                         builder3.setValue(3);
                         builder2.addValues(builder3);

                         VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                         builder4.setId(3);
                         builder4.setValue(1);
                         builder2.addValues(builder4);

                         VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                         builder5.setId(5);
                         builder5.setValue(2);
                         builder2.addValues(builder5);

                         builder1.setSlots(builder2);

                         builder1.setLeader(3);
                         builder1.setHelper(2);

                         sandbox.change(builder1.build());

                         break;
                     }
                     case 51: {
                         // 获得第三关奖励
                         increaseExperience(126, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 51, true);
                         increaseSilver(536, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 51, true);

                         // 让第三关为通过状态（会使第三个任务成为完成状态）
                         stages.finishState(2, false, true);

                         break;
                     }
                     case 54: {
                         // 完成第三个任务
                         quests.submit(2);

                         break;
                     }
                     case 60: {
                         // 升级卡片（1号实例卡）
                         LinkedList<Integer> foodCardInstIds = new LinkedList<Integer>();
                         foodCardInstIds.add(4);
                         cards.strengthen(1, foodCardInstIds, true);

                         break;
                     }
                     /*
                     case 65: {
                         // 转生卡片（1号实例卡）
                         cards.transform(1, null, true);

                         break;
                     }
                      * */
                     case 63: {
                         // 抽卡片（注意：首抽必出紫卡）
                         cards.draw(6, Consts.CARD_DRAW_TYPE_GOLD_ONE_DRAW, true);

                         break;
                     }
                 }

                 guideStep++;
                 if (guideStep > Consts.MAX_GUIDE_STEP) {
                     // 引导结束
                     guideStep = 0;
                 }
               //TODO 跳过教程
                 guideStep = 0;
                 sendMessage(ClientToMapBuilder.buildGuideStepChange(guideStep));
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't move to next guide because wrong param guide step[" + curGuildStep +"] not equal to current guide step[" + guideStep + "]"));
             }
         } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't move to next guide because not in guide"));
         }
     }

     public void talk(int channelType, String msg, int recvPlayerId) {
         if (mapPlayer.endForbidTalkTime <= 0 || GameServer.INSTANCE.getCurrentTime() >= mapPlayer.endForbidTalkTime) {
             S2CTalkProto.Builder talkProtoResp = S2CTalkProto.newBuilder();
             talkProtoResp.setChannelType(channelType);
             talkProtoResp.setMsg(msg);
             talkProtoResp.setSendPlayerId(id);
             talkProtoResp.setSendPlayerName(name);
             if (channelType == Consts.WORLDCHANNEL) {
                 if ((lv >= Consts.ALLOW_TALK_LEVEL) && (GameServer.INSTANCE.getCurrentTime() >= nextWorldTalkTime)) {
                     GameServer.INSTANCE.broadcast(ClientToMapBuilder.buildTalk(talkProtoResp.build().toByteArray()));
                     nextWorldTalkTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;

                     if (MapConfig.INSTANCE.useCYLog == true) {
                         List<String> cyLogList = new ArrayList<String>();
                         cyLogList.add("behaviorMC");
                         cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                         cyLogList.add("KDTY");
                         cyLogList.add(String.valueOf(id));
                         cyLogList.add(name);
                         cyLogList.add("");
                         cyLogList.add("BroadcastDBBehavior");
                         cyLogList.add(msg);
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                     }

                     GameLogger.getlogger().log(GameLogMessageBuilder.buildBroadcastDBBehaviorGameLogMessage(id, msg));
                 }
             } else if (channelType == Consts.PRIVATECHANNEL) {
                 // 查看对话目标是否在黑名单中
                 MapPlayer recvPlayer = GameServer.INSTANCE.players.get(recvPlayerId);
                 if (recvPlayer != null && recvPlayer.human != null) {
                     talkProtoResp.setRecvPlayerId(recvPlayerId);
                     talkProtoResp.setRecvPlayerName(recvPlayer.human.name);
                     List<Integer> charIds = new ArrayList<Integer>(2);
                     charIds.add(id);
                     charIds.add(recvPlayerId);
                     GameServer.INSTANCE.broadcast(charIds, ClientToMapBuilder.buildTalk(talkProtoResp.build().toByteArray()), true);

                     if (MapConfig.INSTANCE.useCYLog == true) {
                         List<String> cyLogList = new ArrayList<String>();
                         cyLogList.add("behaviorMC");
                         cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                         cyLogList.add("KDTY");
                         cyLogList.add(String.valueOf(id));
                         cyLogList.add(name);
                         cyLogList.add("");
                         cyLogList.add("PrivateTalkDBBehavior");
                         cyLogList.add(recvPlayerId + " " + msg);
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                     }
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildPrivateTalkDBBehaviorGameLogMessage(id, recvPlayerId, msg));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't talk in channel[" + channelType + "]"));
             }
         }
     }

     public void increaseExperience(int num, int type, int subType, boolean needSend) {
         if (num > 0) {
             int maxLevel = HumanLevelsConfig.INSTANCE.maxLevel;
             if (lv < maxLevel) {
                 int upLevel = 0;
                 exp += num;

                 if (MapConfig.INSTANCE.useCYLog == true) {
                     List<String> cyLogList = new ArrayList<String>();
                     cyLogList.add("behaviorMC");
                     cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                     cyLogList.add("KDTY");
                     cyLogList.add(String.valueOf(id));
                     cyLogList.add(name);
                     cyLogList.add("");
                     cyLogList.add("GetExperienceDBBehavior");
                     cyLogList.add(type + " " + subType + " " + num);
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                 }
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildGetExperienceDBBehaviorGameLogMessage(id, type, subType, num));

                 int levelupExperience = GameServer.INSTANCE.getHumanLevelupExperience(lv);
                 while ((levelupExperience != -1) && (exp >= levelupExperience) && (lv + upLevel < maxLevel)) {
                     upLevel++;
                     exp -= levelupExperience;
                     levelupExperience = GameServer.INSTANCE.getHumanLevelupExperience(lv + upLevel);
                 }

                 if (lv + upLevel >= maxLevel) {
                     exp = 0;
                 }

                 if (upLevel > 0) {
                     levelup(upLevel, needSend);
                 }
                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildExperienceChange(exp));
                 }
             }
         }
     }

     public void increaseRankExperience(int num, int type, int subType, boolean needSend) {
         if (num > 0) {
             int maxLevel = HumanRanksConfig.INSTANCE.maxRank;
             if (rankLv < maxLevel) {
                 int upLevel = 0;
                 rankExp += num;

                 if (MapConfig.INSTANCE.useCYLog == true) {
                     List<String> cyLogList = new ArrayList<String>();
                     cyLogList.add("behaviorMC");
                     cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                     cyLogList.add("KDTY");
                     cyLogList.add(String.valueOf(id));
                     cyLogList.add(name);
                     cyLogList.add("");
                     cyLogList.add("GetRankExperienceDBBehavior");
                     cyLogList.add(type + " " + subType + " " + num);
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                 }

                 GameLogger.getlogger().log(GameLogMessageBuilder.buildGetRankExperienceDBBehaviorGameLogMessage(id, type, subType, num));

                 int rankLevelupExperience = GameServer.INSTANCE.getHumanRankLevelupExperience(rankLv);
                 while ((rankLevelupExperience != -1) && (rankExp >= rankLevelupExperience) && (rankLv + upLevel < maxLevel)) {
                     upLevel++;
                     rankExp -= rankLevelupExperience;
                     rankLevelupExperience = GameServer.INSTANCE.getHumanRankLevelupExperience(rankLv + upLevel);
                 }

                 if (rankLv + upLevel >= maxLevel) {
                     rankExp = 0;
                 }

                 if (upLevel > 0) {
                     rankLevelup(upLevel, needSend);
                 }
                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildRankExperienceChange(rankExp));
                 }
             }
         }
     }

     public void increaseSilver(int num, int type, int subtype, boolean needSend) {
         if (num > 0) {
             if ((Long.MAX_VALUE - silver) > num) {
                 silver += num;
             } else {
                 silver = Long.MAX_VALUE;
             }
             if (needSend) {
                 sendMessage(ClientToMapBuilder.buildSilverChange(silver));
             }

             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBSilverGameLogMessage(id, type, subtype, num, silver));
         }
     }

     public void decreaseSilver(int num, int type, int subtype, boolean needSend) {
         if (num > 0) {
             silver -= num;
             if (needSend) {
                 sendMessage(ClientToMapBuilder.buildSilverChange(silver));
             }

             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBSilverGameLogMessage(id, type, subtype, -num, silver));
         }
     }

     public void increaseGold(int num1, int num2, int type, int subtype, boolean needSend) {
         if ((num1 > 0) || (num2 > 0)) {
             if (num1 > 0) {
                 if ((Integer.MAX_VALUE - gold1) > num1) {
                     gold1 += num1;
                 } else {
                     gold1 = Integer.MAX_VALUE;
                 }

                 vip.increaseVipExp(num1, needSend);

                 // 修改充值活动状态
                 normalActivity.chargeGold(num1);

                 if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_INCREASE_YELLOWSOUL1) {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CHARGE , num1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));
                 } else {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CHARGE , num1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "CHARGE", 0));
                 }

                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
                 }
             }

             if (num2 > 0) {
                 if ((Integer.MAX_VALUE - gold2) > num2) {
                     gold2 += num2;
                 } else {
                     gold2 = Integer.MAX_VALUE;
                 }

                 if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_INCREASE_YELLOWSOUL2) {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CHARGE , num2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "GM", 0));
                 } else {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_TASK_CHARGE , num2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "" + type + ":" + subtype, 0));
                 }

                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildGold2Change(gold2));
                 }
             }

             if (MapConfig.INSTANCE.useCYLog == true && num1 > 0) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("rechargeMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add(String.valueOf(type));
                 cyLogList.add(String.valueOf(num1));
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_RECHARGE));
             }

             if (MapConfig.INSTANCE.useCYLog == true) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("diamondMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add("");
                 cyLogList.add(String.valueOf(lv));
                 if (num1 > 0) {
                     cyLogList.add("1");
                     cyLogList.add(String.valueOf(num1));
                 }
                 else {
                     cyLogList.add("3");
                     cyLogList.add(String.valueOf(num2));
                 }
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("0");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_DIAMOND));
             }

             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, num1, num2, gold1, gold2, lv));
         }
     }

     public void increaseGold1(String passport, Order order, int status) {
         Order order1 = GameServer.INSTANCE.billings.get(passport);
         if (order1 == order) {
             if (status == 0 || status == 20100) {
                 //int num = (order1.currencyId == 1) ? 10 * order1.amount : order1.amount;
                 int num = order.price * order.amount;
                 increaseGold(num, 0, Consts.SOUL_CHANGE_LOG_TYPE_BILL, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true);
                 NotifySystem.INSTANCE.sendNote(id, new BillNotificationMessage(num), true);
             }
             GameServer.INSTANCE.billings.remove(passport);
             DBMessageQueue.queue().offer(MapDBMessageBuilder.buildSaveBillDBMessage(id, passport, order1, status, Consts.BILL_STEP_FINISH));
             Bill bill = new Bill(id, passport);
             GameServer.INSTANCE.executeBill(bill);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] passport " + passport + "receive bill result but this order isn't exist"));
         }
     }

     public void decreaseGold1(int num, int type, int subtype, boolean needSend) {
         if (num > 0) {
             int totoalDecreaseGold1 = 0;
             if (gold1 > num) {
                 totoalDecreaseGold1 = num;
                 gold1 -= num;
             } else {
                 totoalDecreaseGold1 = gold1;
                 gold1 = 0;
             }

             DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , totoalDecreaseGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));

             if (needSend) {
                 sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
             }
             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, -num, 0, gold1, gold2, lv));
         }
     }

     // 注意：调用该方法前必须确认有足够的黄魂可扣
     public void decreaseGold(int num, int type, int subtype, boolean needSend, boolean isConsume) {
         if (num > 0) {
             int costGold1 = 0;
             int costGold2 = 0;
             int leftnum = num;
             if (gold2 > 0) {
                 if (gold2 >= leftnum) {
                     costGold2 = leftnum;
                     gold2 -= leftnum;
                     leftnum = 0;
                 } else {
                     costGold2 = gold2;
                     leftnum -= gold2;
                     gold2 = 0;
                 }

                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildGold2Change(gold2));
                 }
             }

             if (leftnum > 0) {
                 costGold1 = leftnum;
                 gold1 -= leftnum;
                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
                 }
             }

             if (costGold2 > 0 && costGold1 > 0) {
                 if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "GM", 0));
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));
                 } else {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER , costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "" + type + ":" + subtype, 0));
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER , costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "" + type + ":" + subtype, 0));
                 }
             } else if (costGold2 > 0) {
                 if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER, costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD, "GM", 0));
                 } else {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER, costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD, "" + type + ":" + subtype, 0));
                 }
             } else {
                 if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER, costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD, "GM", 0));
                 } else {
                     DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER, costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD, "" + type + ":" + subtype, 0));
                 }
             }

             if (isConsume) {
                 normalActivity.consumeGold(num);
             }

             if (MapConfig.INSTANCE.useCYLog == true) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("commodityBuyMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add("");
                 cyLogList.add(String.valueOf(lv));
                 cyLogList.add("1");
                 cyLogList.add(String.valueOf(type));
                 cyLogList.add("1");
                 cyLogList.add("1");
                 cyLogList.add(String.valueOf(num));
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("0");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_COMMODITY_BUY));
             }

             if (MapConfig.INSTANCE.useCYLog == true) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("diamondMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add("");
                 cyLogList.add(String.valueOf(lv));
                 cyLogList.add("1");
                 cyLogList.add(String.valueOf(num));
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("0");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_DIAMOND));
             }

             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, -costGold1, -costGold2, gold1, gold2, lv));
         }
     }

     public void buyToken(int num) {
         if ((num > 0) && (num <= MapConfig.INSTANCE.maxTokenNum)) {
             if (token < num) {
                 int increaseNum = num - token;
                 int needGold = increaseNum * MapConfig.INSTANCE.tokenPrice;
                 if (getGold() >= needGold) {
                     decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_BUY_TOKEN, num, true, true);
                     increaseToken(increaseNum, true);

                     // 记录行为日志
                     if (MapConfig.INSTANCE.useCYLog == true) {
                         List<String> cyLogList = new ArrayList<String>();
                         cyLogList.add("behaviorMC");
                         cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                         cyLogList.add("KDTY");
                         cyLogList.add(String.valueOf(id));
                         cyLogList.add(name);
                         cyLogList.add("");
                         cyLogList.add("BuyTokenDBBehavior");
                         cyLogList.add(increaseNum + " " + token);
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                     }

                     GameLogger.getlogger().log(GameLogMessageBuilder.buildBuyTokenDBBehaviorGameLogMessage(id, increaseNum, token));
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't buy token[" + num + "] because not enough gold."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't buy token[" + num + "] because already has."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't buy token[" + num + "] because num error."));
         }
     }

     public void increaseToken(int num, boolean needSend) {
         if (num > 0) {
             if (token < MapConfig.INSTANCE.maxTokenNum) {
                 token += num;
                 if (token > MapConfig.INSTANCE.maxTokenNum) {
                     token = MapConfig.INSTANCE.maxTokenNum;
                 }
                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildTokenChange(token));
                 }
             }
         }
     }

     public void decreaseToken(int num, boolean needSend) {
         if (num > 0) {
             token -= num;
             if (needSend) {
                 sendMessage(ClientToMapBuilder.buildTokenChange(token));
             }
         }
     }

     public void buyEnergy() {
         if (energy < HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy) {
             int needGold = 0;
             int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+ Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
             if (currentDay > lastBuyEnergyDay) {
                 buyEnergyCount = 0;
                 lastBuyEnergyDay = currentDay;
             }

             int pos = 0;
             VipNumGold[] vipNumGolds = MapConfig.INSTANCE.buyEnergyGolds;

             // 根据已使用次数查询对应的VipNumGold对象
             for (pos = 0; pos < vipNumGolds.length; pos++) {
                 if (vipNumGolds[pos].num >= buyEnergyCount+1) {
                     break;
                 }
             }

             if (pos < vipNumGolds.length) {
                 needGold = (vipNumGolds[pos].vip > vip.level)?vipNumGolds[pos].gold:0;

                 if (getGold() >= needGold) {
                     decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_BUY_ENERGY, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true, true);
                     increaseEnergy(Integer.MAX_VALUE, true);    // 补满体力
                     buyEnergyCount ++;
                     sendMessage(ClientToMapBuilder.buildBuyEnergy(buyEnergyCount,lastBuyEnergyDay));

                     // 记录行为日志
                     if (MapConfig.INSTANCE.useCYLog == true) {
                         List<String> cyLogList = new ArrayList<String>();
                         cyLogList.add("behaviorMC");
                         cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                         cyLogList.add("KDTY");
                         cyLogList.add(String.valueOf(id));
                         cyLogList.add(name);
                         cyLogList.add("");
                         cyLogList.add("BuyEnergyDBBehavior");
                         cyLogList.add(buyEnergyCount + " ");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         cyLogList.add("");
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                     }
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildBuyEnergyDBBehaviorGameLogMessage(id, buyEnergyCount));
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't buyEnergy because not enough gold"));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't buyEnergy because times limit"));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't buy energy because energy is full."));
         }
     }

     public void increaseEnergy(int num, boolean needSend) {
         if (num > 0) {
             int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;
             if (energy < maxEnergy) {
                 energy += num;
                 if ((energy <= 0) || (energy > maxEnergy)) {
                     energy = maxEnergy;
                 }
                 if (needSend) {
                     sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
                 }
             }
         }
     }

     public void decreaseEnergy(int num, boolean needSend) {
         if (num > 0) {
             energy -= num;
             if (needSend) {
                 sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
             }
         }
     }

     /**
      * 胜率计算（策划用）
      * @param battleId
      * @param helperCardId
      * @param helperCardLevel
      */
     public void calculateWinRate(int battleId, int helperCardId, int helperCardLevel) {
         PveBattleStaticInfo battleStaticInfo = PveBattlesConfig.INSTANCE.getPveBattleStaticInfo(battleId);

         if (battleStaticInfo != null) {
             CalculateWinRateBattle calculateWinRateBattle = new CalculateWinRateBattle();

             // 取出队长卡片数据
             Card leaderCard = sandbox.slots[sandbox.leader];
             TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

             // 助战者天赋
             CardStaticInfo helperCardStaticInfo = null;
             TalentStaticInfo helperTalentStaticInfo = null;
             if ((helperCardId > 0) && (helperCardLevel > 0)) {
                 helperCardStaticInfo = CardFactories.INSTANCE.getCardFactory(helperCardId).staticInfo;

                 if (helperCardStaticInfo.leaderTalentId != -1) {
                     helperTalentStaticInfo = TalentsConfig.INSTANCE.talentStaticInfos[helperCardStaticInfo.leaderTalentId];
                 }
             }

             // 加入玩家战士
             float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
             float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
             int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
             int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
             for (int i=0; i<6; i++) {
                 Card card = sandbox.slots[i];
                 if (card != null) {
                     Fighter fighter = new Fighter(i, calculateWinRateBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                     calculateWinRateBattle.addFighter(fighter);
                 }
             }

             // 加入助战者
             if ((helperCardId > 0) && (helperCardLevel > 0)) {
                 Fighter fighter = new Fighter(sandbox.helper, calculateWinRateBattle, helperCardStaticInfo, helperCardLevel, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                 calculateWinRateBattle.addFighter(fighter);
             }

             // 加入敌人
             for (PveBattleSlotEnemyConfig enemyConfig : battleStaticInfo.battleEnemySlots) {
                 if (enemyConfig != null) {
                     assert ((enemyConfig.enemyPropabilitys != null) && (enemyConfig.enemyPropabilitys.length > 0));
                     Random random = RandomGenerator.INSTANCE.generator;
                     int tmp = random.nextInt(enemyConfig.enemyPropabilitys[enemyConfig.enemyPropabilitys.length-1].propabilityRange);
                     for (PveBattleSlotEnemyPropability enemyPropability : enemyConfig.enemyPropabilitys) {
                         if (tmp < enemyPropability.propabilityRange) {
                             Fighter fighter = new Fighter(enemyConfig.slotId, calculateWinRateBattle, CardFactories.INSTANCE.getCardFactory(enemyPropability.realId==0?enemyPropability.id:enemyPropability.realId).staticInfo, enemyPropability.level, Long.MAX_VALUE, null, null, enemyConfig.isBoss, 0, 1.0f, 1.0f, 0, 0);
                             calculateWinRateBattle.addFighter(fighter);
                             break;
                         }
                     }
                 }
             }

             GameServer.INSTANCE.executeBattle(calculateWinRateBattle);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't calculate win rate because battle[" + battleId + "] not found."));
         }
     }

     /**
      * 产生战斗结果录像文件
      * @param battleId
      * @param helperCardId
      * @param helperCardLevel
      */
     public void generateBattleResult(int battleId, int helperCardId, int helperCardLevel, String outputFileName) {
         PveBattleStaticInfo battleStaticInfo = PveBattlesConfig.INSTANCE.getPveBattleStaticInfo(battleId);

         if (battleStaticInfo != null) {
             GenerateResultBattle generateResultBattle = new GenerateResultBattle(outputFileName);

             // 取出队长卡片数据
             Card leaderCard = sandbox.slots[sandbox.leader];
             TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

             // 助战者天赋
             CardStaticInfo helperCardStaticInfo = null;
             TalentStaticInfo helperTalentStaticInfo = null;
             if ((helperCardId > 0) && (helperCardLevel > 0)) {
                 helperCardStaticInfo = CardFactories.INSTANCE.getCardFactory(helperCardId).staticInfo;

                 if (helperCardStaticInfo.leaderTalentId != -1) {
                     helperTalentStaticInfo = TalentsConfig.INSTANCE.talentStaticInfos[helperCardStaticInfo.leaderTalentId];
                 }
             }

             float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
             float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
             int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
             int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
             // 加入玩家战士
             for (int i=0; i<6; i++) {
                 Card card = sandbox.slots[i];
                 if (card != null) {
                     Fighter fighter = new Fighter(i, generateResultBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                     generateResultBattle.addFighter(fighter);
                 }
             }

             // 加入助战者
             if ((helperCardId > 0) && (helperCardLevel > 0)) {
                 Fighter fighter = new Fighter(sandbox.helper, generateResultBattle, helperCardStaticInfo, helperCardLevel, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                 generateResultBattle.addFighter(fighter);
             }

             // 加入敌人
             for (PveBattleSlotEnemyConfig enemyConfig : battleStaticInfo.battleEnemySlots) {
                 if (enemyConfig != null) {
                     assert ((enemyConfig.enemyPropabilitys != null) && (enemyConfig.enemyPropabilitys.length > 0));
                     Random random = RandomGenerator.INSTANCE.generator;
                     int tmp = random.nextInt(enemyConfig.enemyPropabilitys[enemyConfig.enemyPropabilitys.length-1].propabilityRange);
                     for (PveBattleSlotEnemyPropability enemyPropability : enemyConfig.enemyPropabilitys) {
                         if (tmp < enemyPropability.propabilityRange) {
                             Fighter fighter = new Fighter(enemyConfig.slotId, generateResultBattle, CardFactories.INSTANCE.getCardFactory(enemyPropability.realId==0?enemyPropability.id:enemyPropability.realId).staticInfo, enemyPropability.level, Long.MAX_VALUE, null, null, enemyConfig.isBoss, 1, 1.0f, 1.0f, 0, 0);
                             generateResultBattle.addFighter(fighter);
                             break;
                         }
                     }
                 }
             }

             GameServer.INSTANCE.executeBattle(generateResultBattle);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't generate battle result because battle[" + battleId + "] not found."));
         }
     }

     public void startPveBattle() {
         if (stage != null) {
             if (!stage.isCurrentBattleExecuting) {
                 if (!stage.isCurrentBattleFinished) {
                     if (stage.currentBattleIndex != -1) {
                         if (!stage.needRevive) {
                             if (GameServer.INSTANCE.getCurrentTime() >= nextBattlePermitTime) {
                                 PveBattle pveBattle = stage.createPveBattle();

                                 GameServer.INSTANCE.executeBattle(pveBattle);

                                 stage.isCurrentBattleExecuting = true;
                             } else {
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                         "Player[" + id + "] can't startOnlyOnce battle because last battle is fighting."));
                             }
                         } else {
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                     "Player[" + id + "] can't startOnlyOnce battle because need revive."));
                         }
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] can't startOnlyOnce battle because no more battle."));
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't startOnlyOnce battle because battle is finished."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_DEBUG,
                         "Player[" + id + "] can't startOnlyOnce battle because battle is executing."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't startOnlyOnce battle out of stage."));
         }
     }

     public void digestCertainReward(CertainRewardInfo rewardInfo, int type, int subType) {
         if (rewardInfo.items != null) {
             for (RewardItemInfo rewardItemInfo : rewardInfo.items) {
                 switch (rewardItemInfo.itemType) {
                     case Consts.REWARD_ITEM_TYPE_CARD: {
                         cards.addCard(rewardItemInfo.itemId, rewardItemInfo.level, 0, true);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_ITEM: {
                         items.addItem(rewardItemInfo.itemId, rewardItemInfo.num, true);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_GOLD: {
                         increaseGold(0, rewardItemInfo.num, type, subType, true);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_SILVER: {
                         increaseSilver(rewardItemInfo.num, type, subType, true);
                         break;
                     }
                 }
             }
         }

         increaseExperience(rewardInfo.experience, type, subType, true);
         increaseEnergy(rewardInfo.energy, true);
         increaseSilver(rewardInfo.silver, type, subType, true);
         increaseGold(0, rewardInfo.gold, type, subType, true);
     }

     private void digestStageBox(boolean needSend) {
         StageBox box = stage.box;

         if (box.experience > 0) {
             increaseExperience(box.experience, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
         }

         if (box.gold > 0) {
             increaseGold(0, box.gold, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
         }

         if (box.silver > 0) {
             increaseSilver(box.silver, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
         }

         if (box.items != null) {
             for (RewardItemInfo rewardItemInfo : box.items) {
                 switch (rewardItemInfo.itemType) {
                     case Consts.REWARD_ITEM_TYPE_CARD: {
                         cards.addCard(rewardItemInfo.itemId, rewardItemInfo.level, 0, needSend);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_ITEM: {
                         items.addItem(rewardItemInfo.itemId, rewardItemInfo.num, needSend);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_GOLD: {
                         increaseGold(0, rewardItemInfo.num, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
                         break;
                     }
                     case Consts.REWARD_ITEM_TYPE_SILVER: {
                         increaseSilver(rewardItemInfo.num, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
                         break;
                     }
                 }
             }
         }
     }

     public void receivePveBattleResult(int stageId, int battleId, LinkedList<RewardItemInfo> rewardItemInfos, BattleResultProto battleResult) {
         if (stage != null) {
             if (stage.isCurrentBattleExecuting) {
                 if (stage.staticInfo.id == stageId) {
                     if (stage.currentBattleIndex == battleId) {
                         stage.isCurrentBattleExecuting = false;

                         if (battleResult.getWinner() == 0) {  // 战斗胜利
                             // 累计战斗掉落
                             stage.box.addItems(rewardItemInfos);
                             stage.isCurrentBattleFinished = true;
                         } else {
                             stage.needRevive = true;
                         }

                         sendMessage(ClientToMapBuilder.buildPveBattleResult(battleResult));

                         nextBattlePermitTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] but is waiting for battle[" + stage.currentBattleIndex + "]."));
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] in different stage[" + stage.staticInfo.id + "]."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] but no battle is running."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] get battle[" + battleId + "] result out of stage[" + stageId + "]."));
         }
     }

     // 升级
     public void levelup(int upLevel, boolean needSend) {
         int oldLv = lv;
         lv += upLevel;

         // 补满体力
         increaseEnergy(Integer.MAX_VALUE, needSend);

         // 补满军令
         increaseToken(MapConfig.INSTANCE.maxTokenNum, needSend);

         GameServer.INSTANCE.briefPlayerInfos.levelupPlayer(id, lv);

         quests.levelup(lv);

         if (needSend) {
             sendMessage(ClientToMapBuilder.buildLevelup(lv));
         }

         // 调整等级列表数据
         PlayerIdsOfLevels.INSTANCE.removePlayerId(oldLv, id);
         PlayerIdsOfLevels.INSTANCE.addPlayerId(lv, id);

         // 更新服中最大玩家等级
         if (lv > GameServer.INSTANCE.maxHumanLevel) {
             GameServer.INSTANCE.maxHumanLevel = lv;
         }

         if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
             if (hegemonyTargets == null) {
                 lastHegemonyPayDay = (int) ((GameServer.INSTANCE.getCurrentTime()+ Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                 hegemonyTargets = new HegemonyTargets(this, null);

                 // 通知客户端争霸列表
                 sendMessage(ClientToMapBuilder.buildHegemonyTargetsChange(hegemonyTargets.buildHegemonyTargetsProto()));
             }
         }

         if (lv >= MapConfig.INSTANCE.openMineLevel) {
             // 若臣属数据不在内存，加载之
             OccupyInfo occupyInfo = OccupyInfos.INSTANCE.getOccupyInfo(id);
             if (occupyInfo == null) {
                 OccupyInfos.INSTANCE.loadOccupyInfoFromDB(id);
             } else if (occupyInfo.inited) {
                 occupyInfo.level = lv;
             }
         }

         if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
             if (training == null) {
                 training = new Training(this, null);
             }
         }

         // 银矿
         if (lv >= MapConfig.INSTANCE.openMineLevel) {
             if (mine == null) {
                 mine = new Mine(this, null);
             }

             // 刷新银矿产量值
             ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseMineProductionChangeMessage(id, mine.getProduction()));
         }

         // 兵营
         if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
             if (barrack == null) {
                 barrack = new Barrack(this, null);
             }
         }

         // 军械所
         if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
             if (ordnance == null) {
                 ordnance = new Ordnance(this, null);
             }
         }

         // 军机处
         if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
             if (council == null) {
                 council = new Council(this, null);
             }
         }

         // 通知朋友等级改变
         broadcastToFriends(ClientToMapBuilder.buildFriendLevelChange(id, lv));

         if (MapConfig.INSTANCE.useCYLog == true) {
             List<String> cyLogList = new ArrayList<String>();
             cyLogList.add("roleMC");
             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
             cyLogList.add("KDTY");
             cyLogList.add(String.valueOf(id));
             cyLogList.add(name);
             cyLogList.add("");
             cyLogList.add(String.valueOf(lv));
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_ROLE));

             cyLogList = new ArrayList<String>();
             cyLogList.add("behaviorMC");
             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
             cyLogList.add("KDTY");
             cyLogList.add(String.valueOf(id));
             cyLogList.add(name);
             cyLogList.add("");
             cyLogList.add("LevelupDBBehavior");
             cyLogList.add(oldLv + " " + lv);
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
         }
         GameLogger.getlogger().log(GameLogMessageBuilder.buildLevelupDBBehaviorGameLogMessage(id, oldLv, lv));
     }

     // 升军衔
     public void rankLevelup(int upLevel, boolean needSend) {
         int oldRankLv = rankLv;
         rankLv += upLevel;

         if (lv >= MapConfig.INSTANCE.openMineLevel) {
             // 若臣属数据不在内存，加载之
             OccupyInfo occupyInfo = OccupyInfos.INSTANCE.getOccupyInfo(id);
             if (occupyInfo == null) {
                 OccupyInfos.INSTANCE.loadOccupyInfoFromDB(id);
             } else if (occupyInfo.inited) {
                 occupyInfo.rank = rankLv;
             }
         }

         // 调整军衔列表数据
         PlayerIdsOfRanks.INSTANCE.removePlayerId(oldRankLv, id);
         PlayerIdsOfRanks.INSTANCE.addPlayerId(rankLv, id);

         // 刷新最高战斗力
         checkMaxPowerChange();

         if (needSend) {
             sendMessage(ClientToMapBuilder.buildRankLevelup(rankLv));
         }

         if (MapConfig.INSTANCE.useCYLog == true) {
             List<String> cyLogList = new ArrayList<String>();
             cyLogList.add("behaviorMC");
             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
             cyLogList.add("KDTY");
             cyLogList.add(String.valueOf(id));
             cyLogList.add(name);
             cyLogList.add("");
             cyLogList.add("RankLevelupDBBehavior");
             cyLogList.add(oldRankLv + " " + rankLv);
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
         }

         GameLogger.getlogger().log(GameLogMessageBuilder.buildRankLevelupDBBehaviorGameLogMessage(id, oldRankLv, rankLv));
     }

     public void update(int difftime) {
         flushTimer.update(difftime); // 数据库更新计时器
     }

     public void enterGame() {
         // 修改简略玩家信息的上线标志
         if (!GameServer.INSTANCE.briefPlayerInfos.setInGame(id)) {
             Card leaderCard = sandbox.slots[sandbox.leader];
             GameServer.INSTANCE.briefPlayerInfos.addBriefPlayerInfo(id, name, lv, leaderCard.staticInfo.id, leaderCard.level, true);
         }

         enterTime = GameServer.INSTANCE.getCurrentTime();
         timeRefresh();
         contSign.sign(false);

         updateTimer = new HumanUpdateTimer();
         // 返回进入游戏角色信息给客户端
         sendMessage(ClientToMapBuilder.buildEnterGameRet(humanProtocolBuilder.buildEnterGameCharProto()));

         Bill bill = new Bill(id, mapPlayer.passport);
         GameServer.INSTANCE.executeBill(bill);
         NotifySystem.INSTANCE.sendAllHumanNotes(this);

         // 获取关系信息
         GameServer.INSTANCE.social.loadRelation(this);

         // 刷新补偿信息
         mails.refresh();

         flushTimer = new FlushDataTimer(mapPlayer);

         // inGame标志在最后设置是因为上面timeRefresh中会发通知（在onEnterGame发包之前），通知系统中会根据inGame标志判断是否立即发包
         inGame = true;

         ip = mapPlayer.channelContext.getRemoteIP();

         // 写登陆日志
         if (MapConfig.INSTANCE.useCYLog == true){
             List<String> cyLogList = new ArrayList<String>();
             cyLogList.add("loginMC");
             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
             cyLogList.add("KDTY");
             cyLogList.add(String.valueOf(id));
             cyLogList.add(name);
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add(String.valueOf(0));
             cyLogList.add("");
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_LOGIN));

             cyLogList = new ArrayList<String>();
             cyLogList.add("userMC");
             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
             cyLogList.add("KDTY");
             cyLogList.add(String.valueOf(id));
             cyLogList.add(name);
             cyLogList.add(String.valueOf(lv));
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add("");
             cyLogList.add(String.valueOf(0));
             cyLogList.add("");
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_USER));
         }

         GameLogger.getlogger().log(GameLogMessageBuilder.buildDBLoginLogoutGameLogMessage(id, lv, true, ip, 0));

         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_DEBUG,
                 "Player["+id+"] enter game."));
     }

     public void leaveGame() {
         if (inGame) {
             updateTimer = null;

             // 清空副本和挑战
             if (stage != null) {
                 if (stage.isCurrentBattleFinished) {
                     stageContinue(false);
                 } else {
                     stage.isCurrentBattleExecuting = false;
                 }
             }

             // 复位争霸战斗状态
             if (hegemonyTargets != null) {
                 hegemonyTargets.isFighting = false;
             }

             // 复位据点战斗状态
             if (baseTargets != null) {
                 if (baseTargets.fightingOccupyInfo != null) {
                     baseTargets.fightingOccupyInfo.fighting = false;
                     baseTargets.fightingOccupyInfo.waitUpWaitingMessage();
                     baseTargets.fightingOccupyInfo = null;
                 }
             }

             // 复位反抗状态
             if (selfOccupyInfo != null) {
                 selfOccupyInfo.fighting = false;
                 selfOccupyInfo.waitUpWaitingMessage();
                 selfOccupyInfo = null;
             }

             leaveTime = GameServer.INSTANCE.getCurrentTime();
             totalOnlineTime += leaveTime - enterTime;
             mapPlayer = null;

             if (relation != null) {
                 // 广播通知follower玩家离线
                 if (!relation.friends.isEmpty()) {
                     ProtobufMessage protobufMessage = ClientToMapBuilder.buildFriendLeft(id);
                     for (Integer friendId : relation.friends.keySet()) {
                         MapPlayer friendPlayer = GameServer.INSTANCE.players.get(friendId);
                         if ((friendPlayer != null) && (friendPlayer.human != null) && (friendPlayer.human.inGame)) {
                             friendPlayer.human.sendMessage(protobufMessage);
                         }
                     }
                 }

                 // 清理好友关系
                 relation.human = null;
                 relation = null;
             }

             // 玩家数据入库
             flushData();

             inGame = false;

             // 修改简略玩家信息的上线标志
             GameServer.INSTANCE.briefPlayerInfos.setOffGame(id);

             // 写登出日志
             if (MapConfig.INSTANCE.useCYLog == true) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("onlineTimeMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add(String.valueOf((leaveTime - enterTime)/ Consts.MILSECOND_1MINITE));
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_ONLINE_TIME));
             }

             GameLogger.getlogger().log(GameLogMessageBuilder.buildDBLoginLogoutGameLogMessage(id, lv, false, ip, leaveTime - enterTime));
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR, "Player[" + id + "] multi-logout!"));
         }
     }

     public void enterActivityStage(int stageId, int helper, int activityId, int activityItemId) {
         if (stage == null) {
             // 判断卡槽是否满
             if (cards.cards.size() < HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].baseCardNum + MapConfig.INSTANCE.vipCardSlotNums[vip.level]) {
                 StageStaticInfo[] stageStaticInfos = StagesConfig.INSTANCE.activityStageStaticInfos;
                 if ((stageId >= 0) && (stageId < stageStaticInfos.length)) {
                     StageStaticInfo stageStaticInfo = stageStaticInfos[stageId];
                     // 判断等级限制
                     if (lv >= stageStaticInfo.levelLimit) {
                         // 判断体力是否满足
                         if (energy >= stageStaticInfo.energyCost) {
                             // 校验助战者
                             BriefPlayerInfo helperInfo = (helper != 0)?getHelperBriefPlayerInfo(helper):null;

                             stage = new ActivityStage(this, stageStaticInfo, helperInfo, activityId, activityItemId);

                             // 通知客户端进入副本
                             sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));

                             // 记录行为日志
                             if (MapConfig.INSTANCE.useCYLog == true) {
                                 List<String> cyLogList = new ArrayList<String>();
                                 cyLogList.add("behaviorMC");
                                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                 cyLogList.add("KDTY");
                                 cyLogList.add(String.valueOf(id));
                                 cyLogList.add(name);
                                 cyLogList.add("");
                                 cyLogList.add("EnterStageDBBehavior");
                                 cyLogList.add(Consts.STAGE_TYPE_ACTIVITY + " " + stageId);
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                             }

                             GameLogger.getlogger().log(GameLogMessageBuilder.buildEnterStageDBBehaviorGameLogMessage(id, Consts.STAGE_TYPE_ACTIVITY, stageId, (helperInfo!=null)?helperInfo.leaderCardId:0, (helperInfo!=null)?helperInfo.leaderCardLevel:0, sandbox.buildSandboxProto().toByteArray()));
                         } else {
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                     "Player[" + id + "] can't enter activity stage["+stageId+"] because not enough energy."));
                         }
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] can't enter activity stage["+stageId+"] because level limit."));
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't enter activity stage["+stageId+"] because stage not exist."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't enter activity stage["+stageId+"] because card slots are full."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't enter activity stage["+stageId+"] when in other stage."));
         }
     }

     /**
      * 进入副本
      */
     public void enterStage(int stageId, boolean isBigStage, int helper) {
         // 判断是否已经在副本中
         if (stage == null) {
             // 判断卡槽是否满
             if (cards.cards.size() < HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].baseCardNum + MapConfig.INSTANCE.vipCardSlotNums[vip.level]) {
                 // 根据类型判断副本是否存在
                 StageStaticInfo[] stageStaticInfos = (isBigStage)? StagesConfig.INSTANCE.bigStageStaticInfos: StagesConfig.INSTANCE.normalStageStaticInfos;
                 if ((stageId >= 0) && (stageId < stageStaticInfos.length)) {
                     StageStaticInfo stageStaticInfo = stageStaticInfos[stageId];
                     // 判断等级限制
                     if (lv >= stageStaticInfo.levelLimit) {
                         // 判断体力是否满足
                         if (energy >= stageStaticInfo.energyCost) {
                             // 若是精英副本，每天只允许进一次
                             if (isBigStage) {
                                 if (!stages.isStagePassed(stageStaticInfo.normalId, false)) {
                                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                             "Player[" + id + "] can't enter big stage["+stageId+"] because normal state[" + stageStaticInfo.normalId + "] not pass."));

                                     return;
                                 } else if (!stages.canEnterBigStage(stageId)) {
                                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                             "Player[" + id + "] can't enter big stage["+stageId+"] more than one times in a day."));

                                     return;
                                 }
                             }

                             // 校验助战者
                             BriefPlayerInfo helperInfo = (helper != 0)?getHelperBriefPlayerInfo(helper):null;

                             stage = new Stage(this, stageStaticInfo, helperInfo);

                             // 通知客户端进入副本
                             sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));

                             // 记录行为日志
                             if (MapConfig.INSTANCE.useCYLog == true) {
                                 List<String> cyLogList = new ArrayList<String>();
                                 cyLogList.add("behaviorMC");
                                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                 cyLogList.add("KDTY");
                                 cyLogList.add(String.valueOf(id));
                                 cyLogList.add(name);
                                 cyLogList.add("");
                                 cyLogList.add("EnterStageDBBehavior");
                                 cyLogList.add((isBigStage ? Consts.STAGE_TYPE_BIG : Consts.STAGE_TYPE_NORMAL) + " " + stageId);
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 cyLogList.add("");
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                             }
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildEnterStageDBBehaviorGameLogMessage(id, isBigStage? Consts.STAGE_TYPE_BIG: Consts.STAGE_TYPE_NORMAL, stageId, (helperInfo!=null)?helperInfo.leaderCardId:0, (helperInfo!=null)?helperInfo.leaderCardLevel:0, sandbox.buildSandboxProto().toByteArray()));
                         } else {
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                     "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because not enough energy."));
                         }
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because level limit."));
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't enter unknown " + (isBigStage?"big":"normal") + " stage["+stageId+"]."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because card slots are full."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + "stage["+stageId+"] when in other stage."));
         }
     }

     private BriefPlayerInfo getHelperBriefPlayerInfo(int helper) {
         // 先从陌生人中查询
         for (BriefPlayerInfo briefPlayerInfo : strangers) {
             if (briefPlayerInfo.id == helper) {
                 return briefPlayerInfo;
             }
         }

         // 再从朋友中查询
         if (relation != null) {
             Long permitTime = relation.friends.get(helper);
             if ((permitTime != null) && (permitTime <= GameServer.INSTANCE.getCurrentTime())) {
                 return GameServer.INSTANCE.briefPlayerInfos.get(helper);
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't select friend["+helper+"] because not cooldown."));
             }
         }

         return null;
     }

     public long nextAllowGetCardDrawActivityListTime;   // 下一次获取商城活动操作许可时间（防止被攻击）
     public void getCardDrawActivityList() {
         long currentTime = GameServer.INSTANCE.getCurrentTime();
         if (currentTime >= nextAllowGetCardDrawActivityListTime) {
             nextAllowGetCardDrawActivityListTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
             sendMessage(ClientToMapBuilder.buildCardDrawActivityList(CardDrawActivityTemplates.INSTANCE.buildCardDrawActivitiesProto()));
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] get card-draw activity list error because not cooldown."));
         }
     }

     public long nextAllowGetStageActivityListTime;   // 下一次获取关卡活动操作许可时间（防止被攻击）
     public void getStageActivityList() {
         long currentTime = GameServer.INSTANCE.getCurrentTime();
         if (currentTime >= nextAllowGetStageActivityListTime) {
             nextAllowGetStageActivityListTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
             sendMessage(ClientToMapBuilder.buildStageActivityList(StageActivityTemplates.INSTANCE.buildStageActivitiesProto()));
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] get stage activity list error because not cooldown."));
         }
     }

     public void changeSandbox(SandboxProto sandboxProto) {
         if (stage != null) {
             sandbox.littleChange(sandboxProto);
         } else {
             sandbox.change(sandboxProto);
         }
     }

     public void changeTraining(IntValuesProto intValuesProto) {
         if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
             training.change(intValuesProto);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't change training because level limit."));
         }
     }

     public void changeBarrack(IntValuesProto intValuesProto) {
         if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
             barrack.change(intValuesProto);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't change barrack because level limit."));
         }
     }

     public void changeOrdnance(IntValuesProto intValuesProto) {
         if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
             ordnance.change(intValuesProto);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't change ordnance because level limit."));
         }
     }

     public void changeCouncil(IntValuesProto intValuesProto) {
         if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
             council.change(intValuesProto);
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't change council because level limit."));
         }
     }

     public void stageContinue(boolean needSend) {
         // 向客户端发当前副本状态
         if (stage != null) {
             if (!stage.isStageFinished) {
                 if (stage.isCurrentBattleFinished) {
                     // 计算下一场战斗阵型
                     stage.moveNext();

                     if (needSend) {
                         sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));
                     }

                     if (stage.isStageFinished) {
                         // 扣体力，加掉落获得，完成并离开副本
                         // 判断是否有体力减半活动
                         if (StageActivityTemplates.INSTANCE.halfEnergy(stage.staticInfo.id)) {
                             decreaseEnergy((stage.staticInfo.energyCost+1)/2, needSend);    // 策划要求上取整
                         } else {
                             decreaseEnergy(stage.staticInfo.energyCost, needSend);
                         }

                         digestStageBox(needSend);

                         switch (stage.staticInfo.type) {
                             case Consts.STAGE_TYPE_NORMAL: {
                                 stages.finishState(stage.staticInfo.id, false, needSend);
                                 break;
                             }
                             case Consts.STAGE_TYPE_BIG: {
                                 stages.finishState(stage.staticInfo.id, true, needSend);
                                 break;
                             }
                             case Consts.STAGE_TYPE_ACTIVITY: {
                                 ActivityStage activityStage = (ActivityStage)stage;
                                 normalActivity.finishState(activityStage.activityId, activityStage.activityItemId);
                                 break;
                             }
                         }

                         // 若助战者是好友，设置冷却
                         if (stage.helperInfo != null) {
                             if (relation != null) {
                                 if (relation.friends.containsKey(stage.helperInfo.id)) {
                                     long cooldownTime = GameServer.INSTANCE.getCurrentTime() + Consts.FRIEND_HELP_COOLDOWN_TIME;
                                     relation.friends.put(stage.helperInfo.id, cooldownTime);

                                     if (needSend) {
                                         sendMessage(ClientToMapBuilder.buildFriendHelpCooldown(stage.helperInfo.id, cooldownTime));
                                     }
                                 }
                             }
                         }

                         // 重新生成陌生人表
                         generateStrangers(needSend);

                         if (needSend) {
                             if (stage.staticInfo.type != Consts.STAGE_TYPE_ACTIVITY) {
                                 sendMessage(ClientToMapBuilder.buildLeaveStage(stage.staticInfo.id, stage.staticInfo.type));
                             } else {
                                 ActivityStage activityStage = (ActivityStage)stage;
                                 sendMessage(ClientToMapBuilder.buildLeaveStage(activityStage.activityId, Consts.STAGE_TYPE_ACTIVITY));
                             }
                         }

                         // 记录行为日志
                         if (MapConfig.INSTANCE.useCYLog == true) {
                             List<String> cyLogList = new ArrayList<String>();
                             cyLogList.add("instanceMC");
                             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                             cyLogList.add("KDTY");
                             cyLogList.add(String.valueOf(id));
                             cyLogList.add(name);
                             cyLogList.add("");
                             cyLogList.add(String.valueOf(lv));
                             cyLogList.add(String.valueOf(stage.staticInfo.type));
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_INSTANCE));

                             cyLogList = new ArrayList<String>();
                             cyLogList.add("behaviorMC");
                             cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                             cyLogList.add("KDTY");
                             cyLogList.add(String.valueOf(id));
                             cyLogList.add(name);
                             cyLogList.add("");
                             cyLogList.add("FinishStageDBBehavior");
                             cyLogList.add(stage.staticInfo.type + " " + stage.staticInfo.id);
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             cyLogList.add("");
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                         }

                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFinishStageDBBehaviorGameLogMessage(id, stage.staticInfo.type, stage.staticInfo.id));
                         stage = null;
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't continue stage because current battle not finish."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't continue stage because stage is finished."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't continue stage out of stage."));
         }
     }

     /**
      * 离开副本
      */
     public void leaveStage() {
         if (stage != null) {
             if (stage.needRevive) {
                 if (stage.staticInfo.type != Consts.STAGE_TYPE_ACTIVITY) {
                     sendMessage(ClientToMapBuilder.buildLeaveStage(stage.staticInfo.id, stage.staticInfo.type));
                 } else {
                     ActivityStage activityStage = (ActivityStage)stage;
                     sendMessage(ClientToMapBuilder.buildLeaveStage(activityStage.activityId, Consts.STAGE_TYPE_ACTIVITY));
                 }

                 // 记录行为日志
                 if (MapConfig.INSTANCE.useCYLog == true) {
                     List<String> cyLogList = new ArrayList<String>();
                     cyLogList.add("behaviorMC");
                     cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                     cyLogList.add("KDTY");
                     cyLogList.add(String.valueOf(id));
                     cyLogList.add(name);
                     cyLogList.add("");
                     cyLogList.add("LeaveStageDBBehavior");
                     cyLogList.add(stage.staticInfo.type + " " + stage.staticInfo.id);
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     cyLogList.add("");
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                 }
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildLeaveStageDBBehaviorGameLogMessage(id, stage.staticInfo.type, stage.staticInfo.id));

                 stage = null;
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't leave stage because not dead."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't leave stage because not in stage."));
         }
     }

     /**
      * 关卡中复活
      */
     public void reviveStage() {
         if (stage != null) {
             stage.revive();
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't revive stage because not in stage."));
         }
     }

     public void striveForHegemony(int targetSlot, boolean stimulate) {
         if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
             if (!hegemonyTargets.isFighting) {
                 if (GameServer.INSTANCE.getCurrentTime() >= nextBattlePermitTime) {
                     if ((targetSlot >=0) && (targetSlot < Consts.MAX_HEGEMONY_TARGET_NUM)) {
                         if ((!stimulate && (token > 0)) || (stimulate && (token >= 3))) {
                             HegemonyTarget target = hegemonyTargets.targets[targetSlot];

                             if (target.status != Consts.HEGEMONY_TARGET_STATUS_WIN) {
                                 // 扣军令
                                 if (stimulate) {
                                     decreaseToken(3, true);
                                 } else {
                                     decreaseToken(1, true);
                                 }

                                 // 产生战斗，并进行计算
                                 HegemonyBattle hegemonyBattle = createHegemonyBattle(targetSlot, stimulate);

                                 GameServer.INSTANCE.executeBattle(hegemonyBattle);

                                 hegemonyTargets.isFighting = true;
                             } else {
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                         "Player[" + id + "] can't strive for hegemony because target slot[" + targetSlot + "] had win."));
                             }
                         } else {
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                     "Player[" + id + "] can't strive for hegemony because no token."));
                         }
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] can't strive for hegemony because target slot[" + targetSlot + "] not exist."));
                     }
                 } else {
                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                             FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                             "Player[" + id + "] can't strive for hegemony because because last battle is fighting."));
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't strive for hegemony because is fighting."));
             }
         } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't strive for hegemony because level limit."));
         }
     }

     public HegemonyBattle createHegemonyBattle(int targetSlot, boolean stimulate) {
         HegemonyTarget target = hegemonyTargets.targets[targetSlot];
         HegemonyBattle hegemonyBattle = new HegemonyBattle(id, targetSlot, target.power, stimulate);

         // 取出队长卡片数据
         Card leaderCard = sandbox.slots[sandbox.leader];
         TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

         float hpChange = (stimulate?0.5f:0) + ((barrack != null)?1.0f+barrack.hpIncrease:1.0f);
         float atkChange = (stimulate?0.5f:0) + ((ordnance != null)?1.0f+ordnance.atkIncrease:1.0f);
         int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
         int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
         // 加入玩家战士
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             Card card = sandbox.slots[i];
             if (card != null) {
                 Fighter fighter = new Fighter(i, hegemonyBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                 hegemonyBattle.addFighter(fighter);
             }
         }

         // 取出对手队长卡片数据
         TargetSandbox targetSandbox = target.sandbox;
         CardStaticInfo targetLeaderCardStaticInfo = CardFactories.INSTANCE.getCardFactory(targetSandbox.slots[targetSandbox.leader].cardId).staticInfo;
         TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCardStaticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCardStaticInfo.leaderTalentId]:null;

         // 加入对手战士，并计算对手总战力
         float targetHpChange = target.hpIncrease + 1.0f;
         float targetAtkChange = target.atkIncrease + 1.0f;
         int targetCriAndTenChange = target.criAndTenIncrease;
         int targetHitAndDodChange = target.hitAndDodIncrease;
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             TargetSandboxCard targetCard = targetSandbox.slots[i];
             if (targetCard != null) {
                 CardStaticInfo cardStaticInfo = CardFactories.INSTANCE.getCardFactory(targetCard.cardId).staticInfo;
                 Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, hegemonyBattle, cardStaticInfo, targetCard.cardLevel, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                 hegemonyBattle.addFighter(fighter);
             }
         }

         return hegemonyBattle;
     }

     public void receiveHegemonyBattleResult(int targetSlot, int targetPower, boolean stimulate, BattleResultProto battleResult) {
         if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
             if (hegemonyTargets.isFighting) {
                 HegemonyTarget target = hegemonyTargets.targets[targetSlot];
                 // 取消战斗状态
                 hegemonyTargets.isFighting = false;

                 nextBattlePermitTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;

                 // 计算战斗奖励及更新状态
                 int rewardSilver = 0;
                 int rewardRankExp = 0;
                 int oldStatus = target.status;
                 int cardDrawId = -1;
                 CardDrawItem cardDrawItem = null;
                 HumanRankConfig humanRankConfig = HumanRanksConfig.INSTANCE.rankConfigs[target.rank-1];
                 if (battleResult.getWinner() == 0) {    // 战斗胜利
                     target.status = Consts.HEGEMONY_TARGET_STATUS_WIN;

                     rewardSilver = (int) (targetPower * humanRankConfig.hegemonySilverCoef);
                     rewardRankExp = (int) (targetPower * humanRankConfig.hegemonyRankExpCoef);

                     // 统计胜利场数，决定是否开卡包
                     int winNum = hegemonyTargets.getWinNum();
                     if (winNum == Consts.MAX_HEGEMONY_TARGET_NUM) {
                         // 全胜开大卡包
                         cardDrawId = MapConfig.INSTANCE.hegemonyBigCardDrawId;
                         CardDrawStaticInfo cardDrawStaticInfo = CardDrawsConfig.INSTANCE.getCardDrawStaticInfo(cardDrawId);
                         cardDrawItem = cardDrawStaticInfo.draw();
                     } else if (winNum % 3 == 0) {
                         // 每赢满3场开小号卡包
                         cardDrawId = MapConfig.INSTANCE.hegemonySmallCardDrawId;
                         CardDrawStaticInfo cardDrawStaticInfo = CardDrawsConfig.INSTANCE.getCardDrawStaticInfo(cardDrawId);
                         cardDrawItem = cardDrawStaticInfo.draw();
                     }
                 } else {
                     target.status = Consts.HEGEMONY_TARGET_STATUS_LOST;

                     rewardSilver = (int) (targetPower * humanRankConfig.hegemonySilverCoef / 2);
                 }

                 // 发送战斗结果给客户端
                 sendMessage(ClientToMapBuilder.buildHegemonyBattleResult(battleResult, stimulate, rewardSilver, rewardRankExp, cardDrawItem, cardDrawId == MapConfig.INSTANCE.hegemonyBigCardDrawId));

                 if (oldStatus != target.status) {
                     // 发送目标状态给客户端
                     sendMessage(ClientToMapBuilder.buildHegemonyTargetStatusChange(targetSlot, target.status));
                 }

                 // 发奖励
                 if (rewardSilver > 0) {
                     increaseSilver(rewardSilver, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY, targetSlot, true);
                 }

                 if (rewardRankExp > 0) {
                     increaseRankExperience(rewardRankExp, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY, targetSlot, true);
                 }

                 // 发宝箱奖励
                 if (cardDrawItem != null) {
                     cards.addCard(cardDrawItem.cardId, cardDrawItem.level, 0, true);
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] get hegemony battle result of target slot[" + targetSlot + "] but no battle is running."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] get hegemony battle result of target slot[" + targetSlot + "] when hegemony not open."));
         }
     }

     public void refreshHegemony(int count) {
         if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
             if (!hegemonyTargets.isFighting) {
                 // 若全胜则免费刷新
                 if (hegemonyTargets.isAllWin()) {
                     hegemonyTargets.refresh();
                 } else {
                     int needGold = 0;
                     int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+ Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                     if (currentDay > lastRefreshHegemonyDay) {
                         refreshHegemonyCount = 0;
                         lastRefreshHegemonyDay = currentDay;
                     }

                     if (refreshHegemonyCount == count) {
                         int pos = 0;
                         VipNumGold[] vipNumGolds = MapConfig.INSTANCE.refreshHegemonyGolds;

                         // 根据已使用次数查询对应的VipNumGold对象
                         for (pos = 0; pos < vipNumGolds.length; pos++) {
                             if (vipNumGolds[pos].num >= refreshHegemonyCount+1) {
                                 break;
                             }
                         }

                         if (pos < vipNumGolds.length) {
                             needGold = (vipNumGolds[pos].vip > vip.level)?vipNumGolds[pos].gold:0;

                             if (getGold() >= needGold) {
                                 decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_REFRESH_HEGEMONY, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true, true);
                                 hegemonyTargets.refresh();    // 刷新争霸列表
                                 refreshHegemonyCount ++;
                                 sendMessage(ClientToMapBuilder.buildRefreshHegemony(refreshHegemonyCount,lastRefreshHegemonyDay));

                                 // 记录行为日志
                                 if (MapConfig.INSTANCE.useCYLog == true) {
                                     List<String> cyLogList = new ArrayList<String>();
                                     cyLogList.add("behaviorMC");
                                     cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                     cyLogList.add("KDTY");
                                     cyLogList.add(String.valueOf(id));
                                     cyLogList.add(name);
                                     cyLogList.add("");
                                     cyLogList.add("RefreshHegemonyDBBehavior");
                                     cyLogList.add(refreshHegemonyCount + "");
                                     cyLogList.add("");
                                     cyLogList.add("");
                                     cyLogList.add("");
                                     cyLogList.add("");
                                     cyLogList.add("");
                                     GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                                 }
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildRefreshHegemonyDBBehaviorGameLogMessage(id, refreshHegemonyCount));
                             } else {
                                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                         "Player[" + id + "] can't refresh hegemony because not enough gold"));
                             }
                         } else {
                             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                     "Player[" + id + "] can't refresh hegemony because times limit"));
                         }
                     } else {
                         GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                 FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                 "Player[" + id + "] can't refresh hegemony because count not match."));
                     }
                 }
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't refresh hegemony because is fighting."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't refresh hegemony because level limit."));
         }
     }

     public void getHegemonyPay() {
         if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
             int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+ Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
             if (currentDay > lastHegemonyPayDay) {
                 lastHegemonyPayDay = currentDay;
                 HumanRankConfig humanRankConfig = HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1];

                 // 发军饷
                 if (humanRankConfig.paySilver > 0) {
                     increaseSilver(humanRankConfig.paySilver, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY_PAY, rankLv, true);
                 }

                 if (humanRankConfig.payGold > 0) {
                     increaseSilver(humanRankConfig.payGold, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY_PAY, rankLv, true);
                 }

                 // 通知客户端
                 sendMessage(ClientToMapBuilder.buildHegemonyGetPay(lastHegemonyPayDay, humanRankConfig.paySilver, humanRankConfig.payGold));
             } else {
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                         FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                         "Player[" + id + "] can't get hegemony pay because already pay."));
             }
         } else {
             GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                     FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                     "Player[" + id + "] can't get hegemony pay because level limit."));
         }
     }

     public void getBaseTargets() {
         if (baseTargets == null) {
             baseTargets = new BaseTargets(this);
         }

         baseTargets.getInfo();
     }

     public BaseAttackBattle createBaseAttackBattle(int targetIndex, int targetId, Human targetHuman) {
         BaseAttackBattle baseAttackBattle = new BaseAttackBattle(id, targetIndex, targetId);

         // 取出队长卡片数据
         Card leaderCard = sandbox.slots[sandbox.leader];
         TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

         float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
         float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
         int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
         int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
         // 加入玩家战士
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             Card card = sandbox.slots[i];
             if (card != null) {
                 Fighter fighter = new Fighter(i, baseAttackBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                 baseAttackBattle.addFighter(fighter);
             }
         }

         // 取出对手队长卡片数据
         SandBox targetSandBox = targetHuman.sandbox;
         Card targetLeaderCard = targetSandBox.slots[targetSandBox.leader];
         TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCard.staticInfo.leaderTalentId]:null;

         float targetHpChange = (targetHuman.barrack != null)?1.0f+targetHuman.barrack.hpIncrease:1.0f;
         float targetAtkChange = (targetHuman.ordnance != null)?1.0f+targetHuman.ordnance.atkIncrease:1.0f;
         int targetCriAndTenChange = (targetHuman.council != null)?targetHuman.council.criAndTenIncrease:0;
         int targetHitAndDodChange = (targetHuman.training != null)?targetHuman.training.hitAndDodIncrease:0;
         // 加入对手战士，并计算对手总战力
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             Card card = targetSandBox.slots[i];
             if (card != null) {
                 Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, baseAttackBattle, card.staticInfo, card.level, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                 baseAttackBattle.addFighter(fighter);
             }
         }

         return baseAttackBattle;
     }

     public BaseResistanceBattle createBaseResistanceBattle(int king, Human targetHuman, boolean stimulate) {
         BaseResistanceBattle baseResistanceBattle = new BaseResistanceBattle(id, king, stimulate);

         // 取出队长卡片数据
         Card leaderCard = sandbox.slots[sandbox.leader];
         TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

         float hpChange = (stimulate?0.5f:0) + ((barrack != null)?1.0f+barrack.hpIncrease:1.0f);
         float atkChange = (stimulate?0.5f:0) + ((ordnance != null)?1.0f+ordnance.atkIncrease:1.0f);
         int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
         int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
         // 加入玩家战士
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             Card card = sandbox.slots[i];
             if (card != null) {
                 Fighter fighter = new Fighter(i, baseResistanceBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                 baseResistanceBattle.addFighter(fighter);
             }
         }

         // 取出对手队长卡片数据
         SandBox targetSandBox = targetHuman.sandbox;
         Card targetLeaderCard = targetSandBox.slots[targetSandBox.leader];
         TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCard.staticInfo.leaderTalentId != -1)? TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCard.staticInfo.leaderTalentId]:null;

         float targetHpChange = (targetHuman.barrack != null)?1.0f+targetHuman.barrack.hpIncrease:1.0f;
         float targetAtkChange = (targetHuman.ordnance != null)?1.0f+targetHuman.ordnance.atkIncrease:1.0f;
         int targetCriAndTenChange = (targetHuman.council != null)?targetHuman.council.criAndTenIncrease:0;
         int targetHitAndDodChange = (targetHuman.training != null)?targetHuman.training.hitAndDodIncrease:0;
         // 加入对手战士，并计算对手总战力
         for (int i = 0; i< Consts.MAX_SANDBOX_SLOT_NUM; i++) {
             Card card = targetSandBox.slots[i];
             if (card != null) {
                 Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, baseResistanceBattle, card.staticInfo, card.level, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                 baseResistanceBattle.addFighter(fighter);
             }
         }

         return baseResistanceBattle;
     }

     public void flushData() {
         // 只有当玩家在线时才需要向数据库同步保存数据
         if (inGame) {
             // 将玩家信息入库
             DBMessageQueue.queue().offer(MapDBMessageBuilder.buildSaveCharInfoDBMessage(id, buildCharDetailInfo()));
         }
     }

     public CharDetailInfo buildCharDetailInfo() {
         CharDetailInfo charDetailInfo = new CharDetailInfo();

         charDetailInfo.mid = id;
         charDetailInfo.name = name;
         charDetailInfo.gold1 = gold1;
         charDetailInfo.gold2 = gold2;
         charDetailInfo.silver = silver;
         charDetailInfo.energy = energy;
         charDetailInfo.token = token;
         charDetailInfo.level = lv;
         charDetailInfo.experience = exp;
         charDetailInfo.rankLevel = rankLv;
         charDetailInfo.rankExperience = rankExp;
         Card leaderCard = sandbox.slots[sandbox.leader];
         charDetailInfo.leaderCardId = leaderCard.staticInfo.id;
         charDetailInfo.leaderCardLevel = leaderCard.level;
         charDetailInfo.vipLevel = vip.level;
         charDetailInfo.vipExperience = vip.exp;
         charDetailInfo.maxPower = maxPower;

         charDetailInfo.detail = humanProtocolBuilder.buildPlayerDetail();
         charDetailInfo.mailInfo = mails.buildDBMailsProto();

         charDetailInfo.totalOnlineTime = totalOnlineTime;
         charDetailInfo.leaveTime = leaveTime;

         return charDetailInfo;
     }

     public void lookOtherPlayerDetailInfo(Human target) {
         if (target != null) {
             // TODO: 发送消息
 //            sendMessage(ClientToMapBuilder.buildOtherPlayerDetail(otherPlayer.humanProtocolBuilder.buildOtherPlayerInfoProto()));

             if (MapConfig.INSTANCE.useCYLog == true) {
                 List<String> cyLogList = new ArrayList<String>();
                 cyLogList.add("behaviorMC");
                 cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                 cyLogList.add("KDTY");
                 cyLogList.add(String.valueOf(id));
                 cyLogList.add(name);
                 cyLogList.add("");
                 cyLogList.add("GetPlayerInfoDBBehavior");
                 cyLogList.add(target.id + "");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 cyLogList.add("");
                 GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogMessage.GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
             }
             GameLogger.getlogger().log(GameLogMessageBuilder.buildGetPlayerInfoDBBehaviorGameLogMessage(id, target.id));
         }
     }

     public void addCouponReward(String code, CertainRewardInfo reward) {
         if(reward != null){
             digestCertainReward(reward, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_COUPON, 0);

             sendMessage(ClientToMapBuilder.buildGetCoupon(reward));
             DBMessageQueue.queue().offer(MapDBMessageBuilder.buildGetCouponDBMessage(id, mapPlayer.passport, code));
         } else {
             // 发失败给客户端
             sendMessage(ClientToMapBuilder.buildGetCouponError());
         }
     }

     public void sendMessage(ProtobufMessage message) {
         if ((mapPlayer != null) && (mapPlayer.channelContext != null))
         {
             mapPlayer.channelContext.write(message);
         }
     }

     public void broadcastToFriends(ProtobufMessage message) {
         if ((relation != null) && !relation.friends.isEmpty()) {
             GameServer.INSTANCE.broadcast(relation.friends, message, true);
         }
     }

     public void increaseEnergyGM() {
         int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].maxEnergy;
         energy = maxEnergy;
         sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
     }

     public void ignoreGuideStep() {
         guideStep = 0;
     }
 }
